package shg.book.socket
{
	import air.net.*;
	
	import com.hurlant.crypto.Crypto;
	import com.hurlant.crypto.symmetric.ICipher;
	
	import flash.data.EncryptedLocalStore;
	import flash.errors.IOError;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.StatusEvent;
	import flash.events.TimerEvent;
	import flash.filesystem.File;
	import flash.filesystem.FileMode;
	import flash.filesystem.FileStream;
	import flash.net.Socket;
	import flash.utils.ByteArray;
	import flash.utils.Timer;
	
	import shg.book.util.ImageLoader;
	import shg.book.util.MD5;

	/**
	 * 	注意事项一：这是表示当服务器启动的是时候有两种可能1.是已经联网2.是没联网。 假如已经联网的话就需要到服务器获取最新的广告
	 * 然后加载从服务器获取到的广告信息并把各个广告信息存储在加密本地存储区，然后把刚刚下载下来的广告转为文件存储在存储目录里面如果没有联网的话就会直接读取本地加密
	 * 存储区的广告信息（如果有的话），然后生成文件存储在存储目录里面
	 * */
	public class ConnectionServer
	{
		private var shgBook:shuhg;
		private var clientSocket:Socket;
		private  var adversitingSocke:Socket;
		private var md5:shg.book.util.MD5;
		private var socketMonitor:SocketMonitor;
		private var time:Timer;
		private var j:uint = 0;
		private var loginSuccese:Boolean=false;
		private var hideProgress:Boolean=false;
		private var adver:String;
		private var loaderFile:ImageLoader;
		//保存加载进来的广告字节码
		private var adversitByte:ByteArray;
		private var name:String="";
		public function ConnectionServer()
		{
		}
		public function initApp(shg:shuhg,adversiting:String):void{
			//初始化局部变量
			shgBook=shg;
			
			if(shgBook.userName.text.length>0&&shgBook.userPassword.text.length>0){
				if(clientSocket==null)
					clientSocket=new Socket();
				
					shgBook.hint.visible=false;
					//开始显示加载滚动条
					progressLogin();
					try{
						//无法连接到网络的时候将会触发这个事件
						clientSocket.addEventListener(IOErrorEvent.IO_ERROR,connectError);
						//注册侦听函数
						clientSocket.addEventListener(Event.CONNECT,onConnect);
						//当收受到来自服务器端的数据的时候
						clientSocket.addEventListener( ProgressEvent.SOCKET_DATA, serverSocketDate );
						clientSocket.connect(SocketDate.SERVER_IP,SocketDate.SERVER_POST);
					}catch(error:Error){
						clientSocket.close();
						trace("连接服务器产生异常"+error.toString());
					}
			}else{
				//如果adversiting为null一定不是广告请求，否则为广告请求
				if(adversiting==null){
					if(shgBook.userName.text.length<1){
						shgBook.hint.text="用户名不能为空";
						shgBook.hint.visible=true;
					}else{
						shgBook.hint.text="密码不能为空";
						shgBook.hint.visible=true;
					}
				}else{
					//变量赋值
					adver=adversiting;
					//发送广告连接请求
					acceptAdver();
				}
			}
		}
		/**
		 * 当连接上服务器之后
		 * 就执行此函数
		 * */
		private function onConnect(event:Event):void{
			var sendStr:String=shgBook.userName.text.toString()+"&"+encrypt(shgBook.userPassword.text.toString());
			//将用户名保存进入静态变量
			name=shgBook.userName.text;
			try{
				event.currentTarget.writeUTFBytes(sendStr);
				event.currentTarget.flush();
			}catch(error:Error){
				event.currentTarget.close();
				trace("向服务器写数据产生异常"+error.toString());
			}
		}
		/**
		 * 登录的网络连接失败产生的异常
		 * */
		private function connectError(event:IOErrorEvent):void{
			time.stop();
			shgBook.progress.visible=false;
			shgBook.hint.text="网络连接失败";
			shgBook.hint.visible=true;
		}
		/**
		 *如果连接不是那个服务器就会在这里产生异常
		 *如果连接不上服务器的话就在本地获取广告信息
		 * 如果本地也没有的话就不做显示
		 * */
		private function adversitingError(event:IOErrorEvent):void{
			if(adversitingSocke!=null){
				adversitingSocke=null;
			}
			//在本地加密存储区加载广告文件
			showAdversit();
		}
		/**
		 * 广告连接上服务器
		 * */
		private function adversitingConnect(event:Event):void{
			try{
				event.currentTarget.writeUTFBytes(adver);
				event.currentTarget.flush();
			}catch(error:Error){
				event.currentTarget.close();
				trace("向服务器写数据产生异常"+error.toString());
			}
		}
		/**
		 * 广告请求的数据返回
		 * */
		private function adversitingDate(event:ProgressEvent):void{
			var buffer:ByteArray = new ByteArray();
			try{
				event.currentTarget.readBytes( buffer, 0, event.currentTarget.bytesAvailable );
				//重新定位
				buffer.position=0;
				//读取键值
				var key:ByteArray = new ByteArray();
				buffer.readBytes(key, 0, 16); 
				//读取密文
				var encryptedBytes:ByteArray = new ByteArray();
				buffer.readBytes(encryptedBytes); 
				//解密
				try{
					var aes:ICipher = Crypto.getCipher("aes-ecb", key, Crypto.getPad("pkcs5"));
					aes.decrypt(encryptedBytes);
					var aesArray:Array=encryptedBytes.toString().split("&");
					for(var i:int=0;i<aesArray.length;i++){
						if(i==0){ 
							loaderFile=new ImageLoader(aesArray[i],SocketDate.adversitTwoKey,i);
							loaderFile.addEventListener(Event.COMPLETE,loaderSwf);
						}else if(i==1){
							loaderFile=new ImageLoader(aesArray[i],SocketDate.adversitOneKey,i);
							loaderFile.addEventListener(Event.COMPLETE,loaderSwf);
						}else if(i==2){
							loaderFile=new ImageLoader(aesArray[i],SocketDate.adversitThreeKey,i);
							loaderFile.addEventListener(Event.COMPLETE,loaderSwf);
						}else if(i==3){
							loaderFile=new ImageLoader(aesArray[i],SocketDate.adversitFourKey,i);
							loaderFile.addEventListener(Event.COMPLETE,loaderSwf);
						}
					}
				}catch(error:Error){
					//重新发送广告请求
					acceptAdver();
					//如果解密出现异常再向服务器发送请求
					trace("解密异常"+error.toString());
					return ;
				}
			}catch(error:Error){
				//重新发送广告请求
				acceptAdver();
				trace("读取服务器端发送过来的广告信息的时候出现异常"+error.toString());
			}
		}
		/**
		 * 发送广告请求，注意这里每调用一次都要创建一次因为中心服务器发送完
		 * 数据后就把socket关闭掉了，如果我在客户端还是调用以前的连接请求的话可能连接不上
		 * */
		private function acceptAdver():void{
			adversitingSocke=new Socket();
			try{
				adversitingSocke.addEventListener(IOErrorEvent.IO_ERROR,adversitingError);
				adversitingSocke.addEventListener(Event.CONNECT,adversitingConnect);
				adversitingSocke.addEventListener(ProgressEvent.SOCKET_DATA,adversitingDate);
				adversitingSocke.connect(SocketDate.SERVER_IP,SocketDate.SERVER_POST);
			}catch(error:Error){
				adversitingSocke.close();
				trace("连接服务器产生异常"+error.toString());
			}
		}
		/**
		 * 当收受到服务器端发送过来的数据后
		 * */
		private function serverSocketDate(event:ProgressEvent):void{
			var buffer:ByteArray = new ByteArray();
			try{
				event.currentTarget.readBytes( buffer, 0, event.currentTarget.bytesAvailable );
				if(buffer.toString()=="_client_close"){
					event.currentTarget.close();
					shgBook.hint.text="此账户已经在异地登录！";
					shgBook.hint.visible=true;
				}else if(buffer.toString()=="true"){
					shgBook.hint.visible=false;
					//如果登录成功将设置为true
					loginSuccese=true;
					//保存用户名进入静态变量
					SocketDate.userName=name;
					//如果连接成功了就需要对网络进行监控
					startMonitor();
				}else if(buffer.toString()=="false"){
					hideProgress=true;
				}
			}catch(error:Error){
				trace("读取服务器端发送过来的消息的时候出现异常"+error.toString());
			}
		}
		/**
		 * 对用户密码进行加密
		 * */
		private function encrypt(password:String):String{
			if(md5==null)
				md5=new MD5();
			return md5.getMD5(password);
		}
		/**
		 * 网络连接状态检测
		 * 它会自动的进行网络测试连接，如果状态发生改变（包括网络可连接或者不可连接）
		 * 就会触发这个StatusEvent.STATUS时间！
		 * */
		private function startMonitor():void{
			if(socketMonitor==null)
				socketMonitor=new SocketMonitor(SocketDate.SERVER_IP,SocketDate.SERVER_POST);

			socketMonitor.addEventListener(StatusEvent.STATUS,statusHandler);
			socketMonitor.start();
		}
		/**
		 * 当网络连接发送改变的时候就会触发这个函数
		 * 这里重新像服务器段发送连接的请求
		 * */
		private function statusHandler(event:StatusEvent):void{
			trace("连接服务器测试咯~~"+clientSocket.connected+" L	"+clientSocket.localAddress+" L  "+clientSocket.localPort+
				" R "+clientSocket.remoteAddress+" R "+clientSocket.remotePort);
			
			if(!clientSocket.connected){
				try{
					clientSocket=null//将其初始化
					clientSocket=new Socket();
					clientSocket.addEventListener(IOErrorEvent.IO_ERROR,connectError);
					//注册侦听函数
					clientSocket.addEventListener(Event.CONNECT,onConnect);
					//当收受到来自服务器端的数据的时候
					clientSocket.addEventListener( ProgressEvent.SOCKET_DATA, serverSocketDate );
					clientSocket.connect(SocketDate.SERVER_IP,SocketDate.SERVER_POST);
				}catch(error:Error){
					clientSocket.close();
					trace("连接服务器产生异常"+error.toString());
				}
			}
		}
		/**
		 * 登录加载进度条显示
		 * 
		 * */
		private function progressLogin():void{
			shgBook.progress.visible=true;
			time=new Timer(50,11);
			time.addEventListener(TimerEvent.TIMER,showProgress);
			time.start();
		}
		/**
		 * 显示加载滚动水银条
		 * */
		private function showProgress(event:TimerEvent):void
		{
			if (j < 100) {
				j += 10;
			} else if (j >= 100) {
				j = 0;
				if(loginSuccese){
					time.stop();
					shgBook.changeLogin();
				}else{
					if(!hideProgress){
						time=new Timer(50,11);
						time.addEventListener(TimerEvent.TIMER,showProgress);
						time.start();
					}else{
						shgBook.progress.visible=false;
						shgBook.hint.text="用户名或密码有误";
						shgBook.hint.visible=true;
					}
				}
			}
			shgBook.progress.setProgress(j, 100);
			shgBook.progress.label="";
		}
		/**
		 * 这是远程加载SWF文件并把加载的文件
		 * 转换为字节码并存储在本地加密文件里面
		 * */
		private function loaderSwf(event:Event):void{
			if(event.currentTarget.adversitName!=null){
				adversitByte=event.currentTarget.byteFile;
				EncryptedLocalStore.removeItem(event.currentTarget.adversitName);
				EncryptedLocalStore.setItem(event.currentTarget.adversitName,adversitByte);
				//将字节写到文件
				writeSWFFile(adversitByte,event.currentTarget.adversitName,event.currentTarget.index)
			}
		}
		/**
		 * 加载本地加密存储区
		 * */
		private function showAdversit():void{
			if(EncryptedLocalStore.getItem(SocketDate.adversitOneKey)!=null){
				writeSWFFile(EncryptedLocalStore.getItem(SocketDate.adversitOneKey),SocketDate.adversitOneKey,0);
			}
			
			if(EncryptedLocalStore.getItem(SocketDate.adversitTwoKey)!=null){
				writeSWFFile(EncryptedLocalStore.getItem(SocketDate.adversitTwoKey),SocketDate.adversitTwoKey,1);
			}
			
			if(EncryptedLocalStore.getItem(SocketDate.adversitThreeKey)!=null){
				writeSWFFile(EncryptedLocalStore.getItem(SocketDate.adversitThreeKey),SocketDate.adversitThreeKey,2);
			}
			
			if(EncryptedLocalStore.getItem(SocketDate.adversitFourKey)!=null){
				writeSWFFile(EncryptedLocalStore.getItem(SocketDate.adversitFourKey),SocketDate.adversitFourKey,3);
			}
		}
		/**
		 * 把传进来的swf字节数据
		 * 写成文件存储在文件里面
		 * 在这里给SocketDate额几个路径变量赋值，目的是当用户
		 * 打开数据的时候首先检查这几个SocketDate的变量是否为
		 * 空，如果存在变量的的就直接应用就可以。不用到服务器获取数据
		 * */
		private function writeSWFFile(byte:ByteArray,name:String,index:Number):void{
			var file:File=File.applicationStorageDirectory;
			file=file.resolvePath(name+".swf");
			SocketDate.adversitPath.addItem(file.nativePath);
			//trace(file.nativePath);
			var filestream:FileStream=new FileStream();
			filestream.open(file,FileMode.WRITE);
			filestream.writeBytes(byte);
			filestream.close();
			if(index==0){
				SocketDate.adversitOne=file.nativePath;
			}else if(index==1){
				SocketDate.adversitTwo=file.nativePath;
			}else if(index==2){
				SocketDate.adversitThree=file.nativePath;
			}else{
				SocketDate.adversitFour=file.nativePath;
			}
		}
	}
}